<?php
/**
 * PHP Zip压缩文件处理类
 * 修改编码格式:统一编码：UTF-8
 * @author Tujt 2015-09-18
 */
class PHPZip {
	private $ctrl_dir     = array();
	private $datasec      = array();
	public $failure_file = array();//失败的文件
	public $zip_file = array();//失败的文件
	public $tem_file = array();//临时文件
	public function  __construct(){
		
    }
	/**
	 * @author Tujt 2015-11-25
	 */
	public function Zip($filelist,$saveName) {
	    if(@!function_exists('gzcompress')){ return; }
		ob_end_clean();
		if(count($filelist) == 0){ return; }

		foreach($filelist as $file){
			if(!file_exists($file) || !is_file($file)){ continue; }
			$fd       = fopen($file, "rb");
			$content  = @fread($fd, filesize($file));
			fclose($fd);
			$file = substr($file, strripos($file,'/')+1);
			if(substr($file, 0, 1) == "\\" || substr($file, 0, 1) == "/"){ $file = substr($file, 1); }
			$this->addFile($content, $file);
		}
		$out = $this->file();

		$fp = fopen($saveName, "wb");
		fwrite($fp, $out, strlen($out));
		fclose($fp);
	}
	public function file_exists($url) {
		$curl = curl_init($url);
		// 不取回数据
		curl_setopt($curl, CURLOPT_NOBODY, true);
		// 发送请求
		$result = curl_exec($curl);
		$found = false;
		// 如果请求没有发送失败
		if ($result !== false) {
		// 再检查http响应码是否为200
		$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
			if ($statusCode == 200) {
				$found = true;
			}
		}
		curl_close($curl);
		return $found;
	}
	/**
	 * @author Tujt 2015-11-25
	 */
	public function FileToZip($filelist,$saveName) {
	    if(@!function_exists('gzcompress')){ return; }
		ob_end_clean();
		if(count($filelist) == 0){ return; }

		foreach($filelist as $file){
			if(!$this->file_exists($file)){ 
				$this->failure_file[] = $file;
				continue;
			}
			$content = $this->getHttp($file);
			$file = substr($file, strripos($file,'/')+1);
			if(substr($file, 0, 1) == "\\" || substr($file, 0, 1) == "/"){ $file = substr($file, 1); }
			$this->addFile($content, $file);
			unset($content);
		}
		$out = $this->file();
		$this->clearTemFiles();//清除临时文件
		$fp = fopen($saveName, "wb");
		fwrite($fp, $out, strlen($out));
		fclose($fp);
		return $out;
	}
	/**
	 * 获取远程数据
	 * @author Tujt 2015-11-26
	 */
	public function getHttp($file) {
		$temfile_name = 'tem_file_'.md5(time()).'.xls';//时间戳并加密，保证文件唯一，不会被其他进程访问
		$temfile = public_path('/upload/reportexcel/reportzip/'.$temfile_name);
		$fp_output = fopen($temfile, 'w');
		$ch = @curl_init($file);
		@curl_setopt($ch, CURLOPT_FILE, $fp_output);
		@curl_exec($ch);
		@curl_close($ch);
		$this->tem_file[$temfile_name] = 1;//记录本次操作的临时文件名，等出来完成后一次性删除
		$content = file_get_contents($temfile);
		return $content;
	}
	/**
	 * 删除xls临时文件
	 * @author Tujt 2015-11-26
	 */
	public function clearTemFiles() {
		if(empty($this->tem_file)) return 0;
	    $tem_dir = public_path('upload/reportexcel/reportzip/');
		chmod($tem_dir, 0777);
		$folder = @opendir($tem_dir);
		if ($folder == false) return 0;
		$count = 0;
		$isfile = array('.'=>'1','..'=>'1','index.html'=>'1','index.htm'=>'1');
		while(false !== ($file = readdir($folder))){
			if(isset($isfile[$file])) continue;//不可删除
			if(is_file($tem_dir.$file) && isset($this->tem_file[$file])){
				if(substr($file,0,9) != 'tem_file_') continue;
				chmod($tem_dir.$file, 0777);
				if (@unlink($tem_dir.$file)) ++$count;
			}
		}
		closedir($folder);unset($this->tem_file);
		return $count;
	}

	/**
	 * 下载
	 * @author Tujt 2015-11-25
	 */
	public function DownloadZip($path) {
	    @header('Content-Encoding: none');
		@header('Content-Type: application/zip');
		@header('Content-Disposition: attachment ; filename=Farticle'.date("YmdHis", time()).'.zip');
		@header('Pragma: no-cache');
		@header('Expires: 0');
		print($path);
	}
	var $old_offset = 0;
	private function addFile($data, $filename, $time = 0)
	{
		$this->zip_file[] = $filename;
		$filename = str_replace('\\', '/', $filename);

		$dtime    = dechex($this->unix2DosTime($time));
		$hexdtime = '\x' . $dtime[6] . $dtime[7]
				  . '\x' . $dtime[4] . $dtime[5]
				  . '\x' . $dtime[2] . $dtime[3]
				  . '\x' . $dtime[0] . $dtime[1];
		eval('$hexdtime = "' . $hexdtime . '";');

		$fr       = "\x50\x4b\x03\x04";
		$fr      .= "\x14\x00";
		$fr      .= "\x00\x00";
		$fr      .= "\x08\x00";
		$fr      .= $hexdtime;
		$unc_len  = strlen($data);
		$crc      = crc32($data);
		$zdata    = gzcompress($data);
		$c_len    = strlen($zdata);
		$zdata    = substr(substr($zdata, 0, strlen($zdata) - 4), 2);
		$fr      .= pack('V', $crc);
		$fr      .= pack('V', $c_len);
		$fr      .= pack('V', $unc_len);
		$fr      .= pack('v', strlen($filename));
		$fr      .= pack('v', 0);
		$fr      .= $filename;

		$fr      .= $zdata;

		$fr      .= pack('V', $crc);
		$fr      .= pack('V', $c_len);
		$fr      .= pack('V', $unc_len);

		$this->datasec[] = $fr;
		$new_offset      = strlen(implode('', $this->datasec));

		$cdrec  = "\x50\x4b\x01\x02";
		$cdrec .= "\x00\x00";
		$cdrec .= "\x14\x00";
		$cdrec .= "\x00\x00";
		$cdrec .= "\x08\x00";
		$cdrec .= $hexdtime;
		$cdrec .= pack('V', $crc);
		$cdrec .= pack('V', $c_len);
		$cdrec .= pack('V', $unc_len);
		$cdrec .= pack('v', strlen($filename) );
		$cdrec .= pack('v', 0 );
		$cdrec .= pack('v', 0 );
		$cdrec .= pack('v', 0 );
		$cdrec .= pack('v', 0 );
		$cdrec .= pack('V', 32 );

		$cdrec .= pack('V', $this->old_offset );
		$this->old_offset = $new_offset;

		$cdrec .= $filename;
		$this->ctrl_dir[] = $cdrec;
	}
	private function unix2DosTime($unixtime = 0)
	{
		$timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);

		if($timearray['year'] < 1980)
		{
			$timearray['year']    = 1980;
			$timearray['mon']     = 1;
			$timearray['mday']    = 1;
			$timearray['hours']   = 0;
			$timearray['minutes'] = 0;
			$timearray['seconds'] = 0;
		}

		return (  ($timearray['year'] - 1980) << 25)
				| ($timearray['mon'] << 21)
				| ($timearray['mday'] << 16)
				| ($timearray['hours'] << 11)
				| ($timearray['minutes'] << 5)
				| ($timearray['seconds'] >> 1);
	}
	var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
	private function file()
	{
		$data    = implode('', $this->datasec);
		$ctrldir = implode('', $this->ctrl_dir);

		return   $data
			   . $ctrldir
			   . $this->eof_ctrl_dir
			   . pack('v', sizeof($this->ctrl_dir))
			   . pack('v', sizeof($this->ctrl_dir))
			   . pack('V', strlen($ctrldir))
			   . pack('V', strlen($data))
			   . "\x00\x00";
	}
}
?>